﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Interactivity;

namespace Slex.Lib.Interactions
{
    /// <summary>
    /// An object that can be listened to a property change notifications
    /// </summary>
    public abstract class PropertyListenerObject : DependencyObject, IAttachedObject
    {

        /// <summary>
        /// The associated object
        /// </summary>
        internal DependencyObject AssociatedObject
        {
            get { return (DependencyObject)GetValue(AssociatedObjectProperty); }
            set { SetValue(AssociatedObjectProperty, value); }
        }

        // Using a DependencyProperty as the backing store for AssociatedObject.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AssociatedObjectProperty =
            DependencyProperty.Register("AssociatedObject", typeof(DependencyObject), typeof(PropertyListenerObject), new PropertyMetadata(null));



        /// <summary>
        /// The type of the property source
        /// </summary>
        public ContextTypeEnum SourceType
        {
            get { return (ContextTypeEnum)GetValue(SourceTypeProperty); }
            set { SetValue(SourceTypeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SourceType.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SourceTypeProperty =
            DependencyProperty.Register("SourceTypeType", typeof(ContextTypeEnum), typeof(PropertyListenerObject), new PropertyMetadata(ContextTypeEnum.Element));



        /// <summary>
        /// Actual binding source of this trigger
        /// </summary>
        protected object Source
        {
            get { return (object)GetValue(SourceProperty); }
            set { SetValue(SourceProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Source.  
        public static readonly DependencyProperty SourceProperty =
            DependencyProperty.Register("Source", typeof(object), typeof(PropertyListenerObject), new PropertyMetadata(null));

        /// <summary>
        /// Name of the property to listen
        /// </summary>
        public string ElementName
        {
            get { return (string)GetValue(ElementNameProperty); }
            set { SetValue(ElementNameProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ElementName.  
        public static readonly DependencyProperty ElementNameProperty =
            DependencyProperty.Register("ElementName", typeof(string), typeof(PropertyListenerObject), new PropertyMetadata("Parent"));

        /// <summary>
        /// The trigger who invoked this action
        /// </summary>
        public SlexTrigger TriggerContext { get; internal set; }


        /// <summary>
        /// The result of the value to compare with. Normally, this is the parameter passed to the trigger
        /// </summary>
        internal object PropertyValue { get; set; }



        /// <summary>
        /// The path to bind to
        /// </summary>
        public string Property
        {
            get { return (string)GetValue(PropertyProperty); }
            set { SetValue(PropertyProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Property.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PropertyProperty =
            DependencyProperty.Register("Property", typeof(string), typeof(PropertyListenerObject), new PropertyMetadata(string.Empty));



        /// <summary>
        /// Callback invoked when the property changes
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="eventArgs"></param>
        private void OnPropertyValueChanged(System.Windows.DependencyObject dependencyObject,
            System.Windows.DependencyPropertyChangedEventArgs eventArgs)
        {
            PropertyValue = eventArgs.NewValue;
        }



        /// <summary>
        /// Does the internal initializations
        /// </summary>
        internal void InternalInitialize()
        {
            if (AssociatedObject != null && Source == null && !string.IsNullOrEmpty(Property))
            {
                if (SourceType == ContextTypeEnum.Element)
                {
                    if (ElementName == "Parent" || string.IsNullOrEmpty(ElementName))
                    {
                        Source = TriggerContext;
                    }
                    else if (ElementName == "This")
                    {
                        Source = AssociatedObject;
                    }
                    else
                        Source = (AssociatedObject as FrameworkElement).FindName(ElementName);
                }
                else if (SourceType == ContextTypeEnum.Model)
                {
                    Source = (AssociatedObject as FrameworkElement).DataContext;
                }

                this.RegisterForNotification
                    (Source, this.Property, OnPropertyValueChanged);
            }

        }


        #region IAttachedObject Members

        DependencyObject IAttachedObject.AssociatedObject
        {
            get { return this.AssociatedObject; }
        }

        public void Attach(DependencyObject dependencyObject)
        {
           //
        }

        public void Detach()
        {
            //
        }

        #endregion
    }
}
